package copyengine.ui.dragdrop.impl.engine
{
	import copyengine.ui.dragdrop.IDragDropEngine;
	import copyengine.ui.dragdrop.IDragDropManger;
	import copyengine.ui.dragdrop.IDragDropSource;
	import copyengine.ui.dragdrop.IDragDropTarget;

	final public class CEDragDropEngine implements IDragDropEngine
	{
		private var dragDropManger:IDragDropManger

		private var currentSource:IDragDropSource;
		private var currentTarget:IDragDropTarget;

		private var dragDropTargetList:Vector.<IDragDropTarget>;

		public function CEDragDropEngine()
		{
			dragDropTargetList = new Vector.<IDragDropTarget>();
		}

		public function set manger(_manger:IDragDropManger):void
		{
			dragDropManger = _manger;
		}

		public function addDragDropTarget(_target:IDragDropTarget):void
		{
			dragDropTargetList.push(_target);
		}

		public function startDragDrop(_source:IDragDropSource, _x:Number, _y:Number):void
		{
			currentSource = _source;

			//dragDropTarget initialize
			for (var i:int = 0; i < dragDropTargetList.length; i++)
			{
				dragDropTargetList[i].engine = this;
			}
			dragDropTargetList.sort(sortDragDropTargetWithHitTestOrder);

			//dragdropSource initialize
			currentSource.engine = this;
			currentTarget = findTargetAtPoint(_x, _y);
			currentSource.onDragDropBegin(currentTarget, _x, _y);
			if (currentTarget != null)
			{
				currentTarget.onDragDropBegin(currentSource, _x, _y);
			}
		}

		public function move(_x:Number, _y:Number):void
		{
			var target:IDragDropTarget = findTargetAtPoint(_x, _y);

			if (currentTarget != target)
			{
				if (currentTarget != null)
				{
					currentSource.onLeaveTarget(currentTarget);
					currentTarget.onSourceLeave(currentSource);
				}
				if (target != null)
				{
					currentSource.onEnterTarget(target);
					target.onSourceEnter(currentSource);
				}
			}
			else
			{
				if (currentTarget != null)
				{
					currentTarget.onSourceMove(currentSource, _x, _y);
				}
			}
			currentTarget = target;
			currentSource.onMove(currentTarget, _x, _y);
		}


		public function dropTarget(_x:Number, _y:Number):void
		{
			//Drop之前先移动到当前Drop点，放置在DragDrop一开始就调用DropTarget函数
			move(_x, _y);
			currentSource.onDrop(currentTarget, _x, _y);
			if (currentTarget != null)
			{
				currentTarget.onSourceDrop(currentSource, _x, _y);
			}
			else
			{
				currentSource.onDragDropCancel();
			}
		}

		public function confirmSourceDrop(_isAccepted:Boolean):void
		{
			currentSource.onDropConfim(currentTarget, _isAccepted);
			endDragDrop();
		}

		/**
		 * drop one source on the ground ,but not finished dragdrop
		 */
		public function endDragDrop():void
		{
			if (currentSource != null)
			{
				currentSource.onDragDropEnd();
			}
			while (dragDropTargetList.length > 0)
			{
				dragDropTargetList.pop().onDragDropEnd();
			}
			dragDropManger.onEndDragDrop();
			currentTarget = null;
			currentSource = null;
		}

		//===============
		//= praivate function
		//===============
		protected function findTargetAtPoint(_x:Number, _y:Number):IDragDropTarget
		{
			for each (var target:IDragDropTarget in dragDropTargetList)
			{
				if (target.isPositionInTarget(_x, _y))
				{
					return target;
				}
			}
			return null;
		}

		private function sortDragDropTargetWithHitTestOrder(_targetA:IDragDropTarget, _targetB:IDragDropTarget):int
		{
			if (_targetA.targetHitTestOrder > _targetB.targetHitTestOrder)
			{
				return -1;
			}
			else
			{
				return 1;
			}
		}

	}
}
